#error This file is for documentation only - DO NOT INCLUDE
/**

@page conditional Conditional operations

When you call a function on one or more [SIMD values](../reference/concepts/simd_value.html#simd_value),
you expect the computation to be performed on every elements of its parameters. Sometimes, you may
want to make the application of a given function dependent on some condition.

Let's explore the functionalities **EVE** provides for achieving those results.

# Explicit Selection
Let's say the function we want to write computes the product of two values `a` and `b` if `a`
is equal to `b` and their difference otherwise.

The scalar code is looking like:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
auto square_or_diff( float a, float  b)
{
  return a == b ? a * b : a - b;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The SIMD version of this code can't use `if` nor the ternary operator directly. The correct approach
is to use the eve::if_else function.

@snippet tutorial/square_or_diff.cpp snippet

The eve::if_else call explicitly requests we pass:
 - the condition, i.e the comparison between `a` and `b`
 - the value to use whenever an element of said condition evaluates to `true`, here the product of `a` and `b`
 - the value to use whenever an element of said condition evaluates to `false`, here the difference of `a` and `b`


@warning  Contrary to a `if ... else` statement, eve::if_else will evaluates all its arguments
          before performing its selection even if potential short-cut can be applied later on.

# Conditional Function Syntax
Let's define a `sqrt_positive` function that computes the square root of its argument if it's positive
or returns it unchanged otherwise. One can write:

@snippet tutorial/sqrt_positive.cpp snippet

This code is perfectly valid and will produce the correct result. However, it has some issues:
 - the code looks like the important part is the test
 - the code can't be optimized in case the current architecture support masked operations (i.e. AVX512 or sve)

To go beyond those limitations, **EVE** functions supports -- whenever it makes sense -- a
conditional call syntax:

@snippet tutorial/sqrt_positive_op.cpp snippet

The code of `sqrt_positive` now works differently:
 - the `a >= 0` expression is evaluated
 - the eve::sqrt[a >= 0] expression builds a new callable object that will perform the conditional
   call to eve::sqrt
 - this bound callable object is then called over `a`
 - Wherever the condition is true, the eve::sqrt function will be applied.
 - Wherever the condition is false, the value of the first argument of the function will be returned.

The fact the conditional syntax builds a new callable object is interesting because it ensures
that any optimization over the conditional computation can be captured and that this new callable
can be passed as-if to algorithms without having to worry about changing the number of arguments
requested.

If required, the callable object produced by the conditional syntax can be stored into a variable:

@snippet tutorial/sqrt_positive_op.cpp snippet-alt

# Conditional Expressions
If passing a simple logical expression is the most common use-case of the conditional syntax, one
may requires more flexibility. To do so, **EVE** provides various objects to express more
elaborated conditions.

## Mask with alternative
One may want to use the conditional syntax to call a function but instead of returning the first
argument if the condition is false, one may want to return an arbitrary value. This use case is
handled by the eve::if_ helper by wrapping logical expression so that an alternative value can be specified.

Let's modify `sqrt_positive` so that, if the argument is not positive, 0 is returned instead.

@snippet tutorial/sqrt_positive_else.cpp snippet

## Context-sensitive mask
Some algorithms require conditional function calls but use logical expression relative to the
element index inside a eve::simd_value rather than its value. One may want for example to not
compute an expression on the first and last element of such eve::simd_value.

A frequent example is trying to load data from memory while ignoring trailing garbage or
out of bounds values:

@snippet tutorial/load_ignore.cpp snippet

Here, the eve::ignore_first and eve::ignore_last conditionals take a number of elements
as parameter that describe which zone of the eve::simd_value won't be affected. By default,
the value of the not loaded lanes are undefined. As for other eve::conditional_expr, we can
affix them with an alternative (99 and 42 respectively) to replace the not loaded pieces.

But what if we want to apply our operation to every element but the first and last one ? Clearly,
calling two operations with two different conditional masks is sub-optimal and **EVE**
provides some more conditional expressions to express this need.

The first is to use the eve::keep_between helper:

@snippet tutorial/load_between.cpp snippet

eve::keep_between uses ad-hoc indexes, which makes the code a bit too size dependent. One can
also use the same conditional but use a similar interface to eve::ignore_first.

@snippet tutorial/load_ignore_both.cpp snippet

The output is obviously the same.

# Conclusion

Conditional operations on [SIMD values](../reference/concepts/simd_value.html#simd_value) is a good way to
keep a high level code over some complex computations. **EVE** provides different levels of abstraction
for such operations as well as various helpers to specify how the conditions can be computed based
either on values or indexes.

**/
